File, Pile et ArrayDeque
La File (Queue) — FIFO
Une file fonctionne selon le principe FIFO : First In, First Out — le premier élément ajouté est le premier à être retiré.
Pense à une file d'attente à la caisse : la première personne arrivée est la première servie. Personne ne peut "couper" la file.
Entrée → [ 3 | 2 | 1 ] → Sortie
↑ ↑
addLast() removeFirst()
Quand l'utiliser ?
- Traitement de tâches dans l'ordre d'arrivée (impression, requêtes réseau)
- Algorithmes de parcours en largeur (BFS)
- Systèmes de messages ou d'événements
BFS (Breadth-First Search) — parcours en largeur :
C'est un algorithme qui explore un graphe ou un arbre niveau par niveau à partir d'un point de départ. Concrètement, imagine chercher la sortie d'un labyrinthe en explorant toutes les directions en même temps, un pas à la fois — ça garantit de trouver le chemin le plus court.
A ← Niveau 0 (départ)
/ \
B C ← Niveau 1
/ \
D E ← Niveau 2
Ordre de visite : A → B → C → D → E
La file est essentielle ici : on ajoute les voisins à la fin (addLast) et on traite toujours depuis le début (removeFirst), ce qui garantit qu'on termine un niveau entier avant de passer au suivant.
Exemple — File d'impression :
ArrayDeque<String> fileImpression = new ArrayDeque<>();
// Trois documents envoyés à l'imprimante
fileImpression.addLast("Document A");
fileImpression.addLast("Document B");
fileImpression.addLast("Document C");
// L'imprimante traite dans l'ordre d'arrivée
while (!fileImpression.isEmpty()) {
System.out.println("Impression : " + fileImpression.removeFirst());
}
// Impression : Document A
// Impression : Document B
// Impression : Document C
La Pile (Stack) — LIFO
Une pile fonctionne selon le principe LIFO : Last In, First Out — le dernier élément ajouté est le premier à être retiré.
Pense à une pile d'assiettes : on pose une assiette par-dessus les autres, et on reprend toujours celle du dessus.
┌───┐ ← push() / addFirst()
│ 3 │ ← sommet (dernier ajouté)
│ 2 │
│ 1 │
└───┘ ← pop() / removeFirst() retire aussi depuis le sommet
Quand l'utiliser ?
- Navigation "retour en arrière" (historique de navigateur, Undo/Redo)
- Évaluation d'expressions mathématiques
- Appels de fonctions récursives (la JVM utilise elle-même une pile d'appels)
Exemple — Historique de navigation :
ArrayDeque<String> historique = new ArrayDeque<>();
// L'utilisateur visite des pages
historique.push("google.com");
historique.push("github.com");
historique.push("stackoverflow.com");
// L'utilisateur appuie sur "retour" trois fois
while (!historique.isEmpty()) {
System.out.println("Retour vers : " + historique.pop());
}
// Retour vers : stackoverflow.com ← dernière page visitée, première retournée
// Retour vers : github.com
// Retour vers : google.com
ArrayDeque — 2 pour 1
ArrayDeque est une implémentation de la classe Deque en Java qui repose sur un tableau dynamique. Elle fait partie du package java.util et est souvent utilisée comme une alternative plus performante à LinkedList pour les opérations de file (queue) et de pile (stack).
Caractéristiques principales :
- Double extrémité : Permet d’ajouter et de supprimer des éléments à la fois au début et à la fin.
- Performances optimisées : Contrairement à
LinkedList, elle évite la surcharge de gestion des noeuds chaînés et offre des opérationsO(1)pouraddFirst(),addLast(),removeFirst()etremoveLast(). - Pas de capacité fixe : Elle s’agrandit dynamiquement en doublant sa taille lorsque nécessaire.
- Non synchronisée : Elle n'est pas thread-safe, donc il faut la synchroniser manuellement en cas d'utilisation concurrente.
Principales méthodes :
- Ajout d’éléments :
deque.addFirst(10); // Ajoute en têtedeque.addLast(20); // Ajoute en queuedeque.offerFirst(30); // Ajoute en tête sans exception si la capacité est atteintedeque.offerLast(40); // Ajoute en queue sans exception
- Suppression d’éléments :
deque.removeFirst(); // Supprime et retourne le premier élémentdeque.removeLast(); // Supprime et retourne le dernier élémentdeque.pollFirst(); // Supprime et retourne le premier élément, ou null si videdeque.pollLast(); // Supprime et retourne le dernier élément, ou null si vide
- Accès sans suppression :
deque.getFirst(); // Retourne le premier élément sans le supprimerdeque.getLast(); // Retourne le dernier élément sans le supprimerdeque.peekFirst(); // Pareil que getFirst() mais retourne null si videdeque.peekLast(); // Pareil que getLast() mais retourne null si vide
- Utilisation comme pile (LIFO) :
deque.push(50); // Ajoute en haut de la piledeque.pop(); // Retire et retourne l'élément du haut de la pile
- Autres :
deque.size(); // Retourne la taille de la dequedeque.isEmpty(); // Vérifie si elle est videdeque.clear(); // Vide la deque
Exemple d’utilisation :
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static void main(String[] args) {
Deque<Integer> deque = new ArrayDeque<>();
deque.addFirst(1);
deque.addLast(2);
deque.addLast(3);
System.out.println(deque); // [1, 2, 3]
System.out.println(deque.removeFirst()); // 1
System.out.println(deque.removeLast()); // 3
System.out.println(deque); // [2]
}
}
Complexité des opérations
| Opération | File (FIFO) | Pile (LIFO) | Deque |
|---|---|---|---|
Ajout (addLast / push / addFirst) | O(1) amortie | O(1) amortie | O(1) amortie |
Suppression (removeFirst / pop / removeLast) | O(1) | O(1) | O(1) |
Accès au sommet/tête (getFirst / getLast) | O(1) | O(1) | O(1) |
Recherche (contains) | O(n) | O(n) | O(n) |
Taille (size) | O(1) | O(1) | O(1) |
Quand utiliser ArrayDeque ?
- Lorsqu'on a besoin d'une pile (LIFO) ou d'une file à double extrémité (FIFO) performante.
- Lorsqu'on veut éviter la surcharge mémoire et la complexité d'un
LinkedList. - Quand on veut une alternative plus efficace que
Stackpour une pile.
ArrayDeque est particulièrement utile lorsqu'on a besoin d'une structure de données performante pour gérer des éléments de manière dynamique, avec des accès rapides aux extrémités. Voici quelques scénarios concrets où elle vaut la peine d’être utilisée :
1. Système de gestion des tâches (Scheduler)
Cas d’usage : Une application qui gère une file de tâches à traiter, avec la possibilité d'ajouter des tâches en priorité (au début) ou en arrière-plan (à la fin).
2. Parcours en largeur d'un graphe (BFS)
Cas d’usage : Algorithme de recherche pour trouver le chemin le plus court dans un labyrinthe ou une carte.
3. Implémentation d'un "Undo/Redo"
Cas d’usage : Un éditeur de texte qui doit gérer l’annulation et la réapplication des actions de l’utilisateur.
4. Traitement des requêtes dans un serveur
Cas d’usage : Un serveur web qui gère les requêtes entrantes en mode FIFO — la première requête reçue est la première traitée.
Pourquoi ArrayDeque ?
addLast()/removeFirst()simulent parfaitement une file.- Plus performant que
LinkedListpour ce type d’accès séquentiel.